#include <stdio.h>
#include <string>
#include <hash_map>
#include <iostream>
#include "hse_common.h"
#include "hse_types.h"
#include "document_meta_datas.h"

namespace hse {

using std::string;
using stdext::hash_map;
using std::cout;
using std::endl;

DocumentMetaDatas *DocumentMetaDatas::instance_ = NULL;

//TODO:add file cache
string DocumentMetaDatas::GetContent(int doc_id, int start_pos, int length) {
	if (length > MAX_CONTENT_LEN) {
		LOG_WARN(printf("change too long content length %d to %d\n", length, MAX_CONTENT_LEN));
	}
	hash_map<int, DocumentMetaData*>::iterator metai = metas_.find(doc_id);
	if (metai == metas_.end()) //empty content
		return string();
	DocumentMetaData& meta = *(metai->second);
	char buffer[MAX_CONTENT_LEN];
	FILE *f = fopen(meta.full_name.c_str(), "r");
	fseek(f, start_pos, SEEK_SET);
	int readed = fread(buffer, 1, length, f);
	fclose(f);
	return string(buffer, readed);
}

void DocumentMetaDatas::AddMetaData(DocumentMetaData& meta) {
	DocumentMetaData *cpy = new DocumentMetaData;
	*cpy = meta;
	metas_[meta.doc_id] = cpy;
	total_dl_ += meta.word_count;
	total_document_++;
}

DocumentMetaData* DocumentMetaDatas::GetMetaData(int doc_id) {
	hash_map<int, DocumentMetaData*>::iterator metai = metas_.find(doc_id);
	if (metai == metas_.end()) //empty content
		return NULL;
	else
		return metai->second;
}

/**
 *
 struct DocumentMetaData {
	int doc_id;
	string name;
	int word_count;
	int length;
	string full_name;
	unsigned char type;
	double k;
};
avdl total_document\n
doc_name has no space, so we can simple store it like this:
doc_id word_count length type full_name name \n
*/
//TODO:iobuf
void DocumentMetaDatas::Dump(FILE *f) {
	LOG_INFO(cout << "Dump document meta data:..." << endl);
	avdl_ = (double) total_dl_ / total_document_;
	fprintf(f, "%f %d\n", avdl_, total_document_);
	hash_map<int, DocumentMetaData*>::iterator metai = metas_.begin();
	for(;metai != metas_.end(); metai++) {
		DocumentMetaData& m = *(metai->second);
		m.k = BM25_k1 * ((1 - BM25_b) + BM25_b * (m.word_count) / avdl_);
		fprintf(f, "%d %d %d %c %s %s %f\n", m.doc_id, m.word_count, m.length, m.type, 
			m.full_name.c_str(), m.name.c_str(), m.k);
	}
	fclose(f);
}

void DocumentMetaDatas::Load(FILE *f) {
	LOG_INFO(cout << "Load document meta data:..." << endl);
	fscanf(f, "%lf %d", &avdl_, &total_document_);
	DocumentMetaData* m = new DocumentMetaData;
	char n1[1024], n2[1024];
	while(fscanf(f, "%d %d %d %c %s %s %lf", &(m->doc_id), &(m->word_count), &(m->length), &(m->type),
		n1, n2, &(m->k)) > 0) {
			m->full_name = n1;
			m->name = n2;
			metas_[m->doc_id] = m;
			m = new DocumentMetaData;
	}
	delete m;
}

DocumentMetaDatas::~DocumentMetaDatas() {
	hash_map<int, DocumentMetaData*>::iterator metai = metas_.begin();
	for(;metai != metas_.end(); metai++)
		delete metai->second;
}

}